package com.innovation.ic.im.end.web.endpoint;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.innovation.ic.b1b.framework.manager.RedisManager;
import com.innovation.ic.b1b.framework.util.StringUtils;
import com.innovation.ic.im.end.base.model.im_erp9.GroupMessage;
import com.innovation.ic.im.end.base.pojo.constant.Constants;
import com.innovation.ic.im.end.base.pojo.constant.RabbitMqExchangeMap;
import com.innovation.ic.im.end.base.pojo.constant.RedisStorage;
import com.innovation.ic.im.end.base.pojo.constant.UserLoginType;
import com.innovation.ic.im.end.base.handler.helper.HandlerHelper;
import com.innovation.ic.im.end.base.handler.im_erp9.WebSocketHandler;
import com.innovation.ic.im.end.base.thread.web.SaveUserLoginLogThread;
import com.innovation.ic.im.end.base.vo.im_erp9.GroupMessageVo;
import com.innovation.ic.im.end.base.vo.im_erp9.LoginTypeVo;
import com.innovation.ic.im.end.web.config.GetHttpSessionConfigurator;
import com.innovation.ic.im.end.web.thread.*;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.*;

@Data
@Component
@ServerEndpoint(value = "/ws/v1/group/{groupId}/{username}", configurator = GetHttpSessionConfigurator.class)
public class GroupEndpoint extends AbstractEndpoint {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    protected RedisManager redisManager;

    /**
     * 与客户端的链接会话，需要通过它给客户端发送数据
     */
    public Session session;

    private String groupId;

    public String account;

    public String userNameStr;

    /**
     * 建立连接
     *
     * @param username
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("groupId") String groupId, @PathParam("username") String username, Session session, EndpointConfig config) {
        Map<String, Object> userProperties = session.getUserProperties();

        // 验证参数
        if (!StringUtils.validateParameter(username)) {
            logger.warn("参数username不能为空");
            return;
        }
        if (null == groupId) {
            logger.warn("参数groupId不能为空");
            return;
        }

        // 获取登录类型
        Integer loginType = getLoginType(userProperties);
        LoginTypeVo loginTypeVo = new LoginTypeVo(username, loginType);
        String usernameStr = JSONObject.toJSON(loginTypeVo).toString();

        // 把自己的信息加入到map当中去
        this.session = session;
        this.groupId = groupId;
        this.account = username;
        this.userNameStr = usernameStr;
        if (null == onlineGroupMap.get(groupId)) {
            Set<GroupEndpoint> set = new HashSet<>();
            set.add(this);
            onlineGroupMap.put(groupId, set);
        } else {
            Set<GroupEndpoint> groupEndpoints = onlineGroupMap.get(groupId);
            boolean ifHave = Boolean.FALSE;
            for (GroupEndpoint groupEndpoint : groupEndpoints) {
                if (groupEndpoint.getUserNameStr().equals(userNameStr)) {
                    ifHave = true;
                    break;
                }
            }
            if (!ifHave) {
                onlineGroupMap.get(groupId).add(this);
            }
        }

        // redis存的键
        String redisKey = RedisStorage.ONLINE_GROUP_MAP + ":" + groupId;
        WebSocketHandler webSocketHandler = HandlerHelper.getWebSocketHandler();
        // 获取Endpoint类中的onlineMap对象判断用户是否已登录
        Set<String> onlineGroupMap = webSocketHandler.getOnlineMap(redisKey);
        if (onlineGroupMap != null && onlineGroupMap.size() > 0) {
            boolean result = Boolean.FALSE;
            for (String data : onlineGroupMap) {
                if (data.contains(usernameStr)) {
                    result = Boolean.TRUE;
                    break;
                }
            }
            if (!result) {
                // 记录用户登录信息
                JSONObject json = new JSONObject();
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(Constants.LOGGER, JSON.toJSONString(this.getLogger()));
                json.put(userNameStr, jsonObject.toString());
                webSocketHandler.putOnlineGroupMap(redisKey, json);
            }
        } else {
            // 记录用户登录信息
            JSONObject json = new JSONObject();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(Constants.LOGGER, JSON.toJSONString(this.getLogger()));
            json.put(userNameStr, jsonObject.toString());
            webSocketHandler.putOnlineGroupMap(redisKey, json);
        }
        logger.info("session的id为【" + session.getId() + "】，参数groupId为【" + groupId + "】，" + "参数username为【" + username + "】，当前群组在线人数【" + onlineGroupMap.size() + "】");

        // 进行记录用户登录信息
        String ipAddr = (String) userProperties.get(UserLoginType.IP_ADDR);
        logger.info("当前请求ip为" + ipAddr);
        SaveUserLoginLogThread saveUserLoginLogThread = new SaveUserLoginLogThread(username, groupId, UserLoginType.DEFAULT_GROUP, ipAddr);
        threadPoolManager.execute(saveUserLoginLogThread);
    }

    /**
     * 报错
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose() {
        Iterator iterator = onlineGroupMap.keySet().iterator();
        while (iterator.hasNext()) {
            String groupId = (String) iterator.next();
            Set<GroupEndpoint> groupEndpointSet = onlineGroupMap.get(groupId);
            if (groupEndpointSet.size() > 0) {
                HashSet<GroupEndpoint> onlineUserSet = new HashSet<>();
                for (GroupEndpoint groupEndpoint : groupEndpointSet) {
                    if (groupEndpoint.getUserNameStr().equals(this.userNameStr)) {
                        // 用户账号account对应用户组groupId的登录对象从redis中删除
                        Long onlineAccountCount = delOnlineGroupMapFromRedis(userNameStr, groupId);
                        logger.info("用户【" + groupEndpoint.account + "】关闭了群组【" + groupEndpoint.groupId + "】，当前在线人数:【" + onlineAccountCount + "】");
                    } else {
                        onlineUserSet.add(groupEndpoint);
                    }
                }
                onlineGroupMap.remove(groupId);
                if (onlineUserSet.size() > 0) {
                    onlineGroupMap.put(groupId, onlineUserSet);
                }
            }
        }
    }

    /**
     * 用户账号account对应用户组groupId的登录对象从redis中删除
     *
     * @param account 用户账号
     * @param groupId 用户组id
     * @return 返回当前群组在线人数
     */
    private Long delOnlineGroupMapFromRedis(String account, String groupId) {
        WebSocketHandler webSocketHandler = HandlerHelper.getWebSocketHandler();
        String redisKey = RedisStorage.ONLINE_GROUP_MAP + ":" + groupId;
        // 根据键值从redis中取onlineMap数据
        Set<String> redisData = webSocketHandler.getOnlineMap(redisKey);
        if (redisData != null && !redisData.isEmpty()) {
            boolean delFlag = Boolean.FALSE;
            for (String data : redisData) {
                if (data.contains(account)) {
                    Long result = webSocketHandler.delOnlineMapValue(redisKey, data);
                    if (result.intValue() == 1) {
                        logger.info("用户:[{}]的群组:[{}]登录信息已从redis中删除", account, groupId);
                        delFlag = Boolean.TRUE;
                        break;
                    }
                }
            }
            if (!delFlag) {
                logger.info("用户:[{}]的群组:[{}]登录信息未从redis中查到,无法删除", account, groupId);
            }
        } else {
            logger.info("redis中不存在用户:[{}]的群组:[{}]登录信息,不进行删除操作", account, groupId);
        }
        // 获取当前群组在线人数
        return webSocketHandler.getRedisKeySize(redisKey);
    }

    /**
     * 收到客户端A的消息，将其发送给群组中所有已经上线的成员。对于还没有上线的成员，则暂时将消息存储在数据库中
     *
     * @param messageString 消息
     * @param session       会话
     */
    @OnMessage
    public void onMessage(String messageString, Session session) {
        // 验证参数
        if (!StringUtils.validateParameter(messageString)) {
            logger.warn("参数messageString不能为空");
            return;
        }
        GroupMessageVo groupMessageVo = JSON.parseObject(messageString, GroupMessageVo.class);
        // type为-1时表示心跳，前端每隔5秒发送一次心跳，以免1分钟后websocket自动断开连接
        if (groupMessageVo.getType() == -1) {
            return;
        }
        if (!StringUtils.validateParameter(groupMessageVo.getContent())
                || !StringUtils.validateParameter(groupMessageVo.getFromUserAccount())
                || null == groupMessageVo.getGroupId()
                || null == groupMessageVo.getType()) {
            logger.warn("参数content、groupId、fromUserAccount和type不能为空");
            return;
        }
        logger.info("来自用户的消息【" + messageString + "】，客户端的session的id是【" + session.getId() + "】");

        // 获取在线用户
        Set<GroupEndpoint> groupEndpointSet = onlineGroupMap.get(groupMessageVo.getGroupId().toString());
        Iterator<GroupEndpoint> groupEndpointIterator = groupEndpointSet.iterator();
        List<String> onlineAccountList = new ArrayList<String>();
        while (groupEndpointIterator.hasNext()) {
            GroupEndpoint groupEndpoint = groupEndpointIterator.next();
            onlineAccountList.add(groupEndpoint.account);
        }

        // 保存群组消息
        GroupMessage groupMessage = modelHandler.toGroupMessage(groupMessageVo);
        Long waitingLockTime = zookeeperParamConfig.getWaitingLockTime();
        SaveGroupMessageThread saveGroupMessageThread = new SaveGroupMessageThread(groupMessage, curatorFramework, waitingLockTime, onlineAccountList,
                rabbitMqParamConfig.getExchange().get(RabbitMqExchangeMap.CURRENT_EXCHANGE), groupMessageVo, onlineGroupMap, threadPoolManager);
        threadPoolManager.execute(saveGroupMessageThread);
    }
}